package com.lsh.oms.core.records;

import com.google.common.collect.Lists;
import com.lsh.oms.core.dao.other.ReturnMapper;
import com.lsh.oms.core.records.core.Return;
import com.lsh.oms.core.records.core.ReturnRequest;
import com.lsh.oms.core.service.tool.Criteria;
import com.lsh.oms.core.service.tool.Criterias;
import com.lsh.oms.core.service.tool.Pageable;
import com.lsh.oms.core.service.tool.Summaries;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Stream;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

@Component
public class ReturnRepository implements com.lsh.oms.core.records.core.ReturnRepository {

    @Resource
    private ReturnMapper mapper;

    @Override
    public Pageable query(Criteria criteria, long page, long pageLimit) {
        Long count = mapper.countBaseOnCriteria(criteria);
        List<Return> result = count > 0
                ? mapper.findBaseOnCriteria(criteria, Pageable.start(page, pageLimit), pageLimit)
                : Collections.emptyList();
        fillDetails(criteria, result);
        return new Pageable<>(result, page, pageLimit, count);
    }

    private void fillDetails(Criteria criteria, List<Return> records) {
        if (Criterias.detailsRequired(criteria)) {
            Map<Long, List<Return.ReturnDetail>> group = findDetails(records.stream().map(Return::id).collect(toList()))
                    .stream().collect(groupingBy($ -> $.returnId()));
            records.forEach($ -> $.fillDetails(group.get($.id())));
        }
    }

    private List<Return.ReturnDetail> findDetails(Collection<Long> returnIds) {
        return returnIds.isEmpty() ? Collections.emptyList() : mapper.findDetails(returnIds);
    }

    @Override
    public Optional<Return> find(Long id, boolean detailsRequired) {
        Return order = mapper.findById(id);
        if (order == null) {
            return Optional.empty();
        }
        if (detailsRequired) {
            ((ReturnRecord) order).details = findDetails(Lists.newArrayList(id));
        }
        return Optional.of(order);
    }

    @Override
    public Optional<Return> find(Long id) {
        return find(id, true);
    }

    @Override
    public Map<String, Long> summary(Criteria criteria) {
        criteria.remove("status");
        Map<String, Long> result = Summaries.enhance(mapper.groupByStatus(criteria));
        Stream.of(Return.Status.values()).forEach($ -> {
            String key = Summaries.key($.name());
            if (!result.containsKey(key)) {
                result.put(key, 0L);
            }
        });
        return result;
    }
}
